//
//  NSDictionary+MZCompatible.m
//  MZToolkitDemo
//
//  Created by Chris Yang on 2017/2/16.
//  Copyright © 2017年 Chris Yang. All rights reserved.
//

#import "NSDecimalNumber+MZBase.h"
#import "NSDictionary+MZCompatible.h"

static BOOL gEnableDefaultVal = YES;

@implementation NSDictionary(MZCompatible)

+ (BOOL)enableDefaultVal {
    return gEnableDefaultVal;
}

+ (void)setEnableDefaultVal:(BOOL)enabled {
    gEnableDefaultVal = enabled;
}

#pragma mark - Safe Interface

- (id)mzNumberObjectForKey:(id<NSCopying>)key {
    
    id tmpData = [self _mzObjectForKey:key
                        withDefaultVal:@(0)
                         expectedClass:[NSNumber class]
                       acceptedClasses:@[[NSString class]]
                            dataHandle:^(id data) {
                                
                                if ([data isKindOfClass:[NSString class]]) {
                                    data = @([data doubleValue]);
                                }
                                return data;
                            }];
    return tmpData;
}

- (id)mzDecimalNumberObjectForKey:(id<NSCopying>)key {
    
    id tmpData = [self _mzObjectForKey:key
                        withDefaultVal:mzDecimalInitVal
                         expectedClass:[NSNumber class]
                       acceptedClasses:@[[NSString class]]
                            dataHandle:^(id data) {
                                
                                if ([data isKindOfClass:[NSNumber class]]) {
                                    data = [NSDecimalNumber mzDecimalNumberFromNumber:data];
                                } else if ([data isKindOfClass:[NSString class]]) {
                                    data = [NSDecimalNumber mzDecimalNumberFromNSString:data];
                                }
                                return data;
                            }];
    return tmpData;
}

- (id)mzStringObjectForKey:(id<NSCopying>)key {
    
    id tmpData = [self _mzObjectForKey:key
                        withDefaultVal:@""
                         expectedClass:[NSString class]
                       acceptedClasses:nil
                            dataHandle:nil];
    return tmpData;
}

- (id)mzArrayObjectForKey:(id<NSCopying>)key {
    
    id tmpData = [self _mzObjectForKey:key
                        withDefaultVal:@[]
                         expectedClass:[NSArray class]
                       acceptedClasses:nil
                            dataHandle:nil];
    return tmpData;
}

- (id)mzDictionaryObjectForKey:(id<NSCopying>)key {
    
    id tmpData = [self _mzObjectForKey:key
                        withDefaultVal:@{}
                         expectedClass:[NSDictionary class]
                       acceptedClasses:nil
                            dataHandle:nil];
    return tmpData;
}

#pragma mark - MISC

- (id)_mzObjectForKey:(id<NSCopying>)key
       withDefaultVal:(id)defalutVal
        expectedClass:(Class)expClass
      acceptedClasses:(NSArray<Class> *)accClassArray
           dataHandle:(id(^)(id data))dataHandel {
    
    NSError *tmpErr = nil;
    id tmpData = [self objectForKey:key];
    
    /* 错误处理 */
    if (nil == tmpData) {
        
        tmpErr = [self invalidKeyErrorWithKey:key];
        
    } else if (NO == [tmpData isKindOfClass:expClass]
               && NO == [self isData:tmpData fitClassWithClassArray:accClassArray]) {
        
        tmpErr = [self wrongClassErrorWithKey:key
                                     valClass:[tmpData class]
                                expectedClass:expClass];
        
    }
    
    /* 存在错误 & 不允许错误时设定默认值 --> 反馈错误 */
    if (nil != tmpErr) {
        if (NO == gEnableDefaultVal) {
            return tmpErr;
        }
        
        /* 设定默认值 */
        tmpData = defalutVal;
    }
    
    if (nil != dataHandel) {
        tmpData = dataHandel(tmpData);
    }
    
    return tmpData;
}

- (BOOL)isData:(id)data fitClassWithClassArray:(NSArray *)classArray {
    
    for (Class tmpClass in classArray) {
        if (YES == [data isKindOfClass:tmpClass]) {
            return YES;
        }
    }
    
    return NO;
}

- (NSError *)invalidKeyErrorWithKey:(id<NSCopying>)key {
    
    NSString *reasonStr = [NSString stringWithFormat:@"key(%@)在字典中不存在对应的值", key];
    NSDictionary *errInfo = @{
                              NSLocalizedFailureReasonErrorKey:reasonStr,
                              };
    
    NSError *error = [NSError errorWithDomain:@"无效的Key"
                                         code:MZSafeDicErrorInvalidedKey
                                     userInfo:errInfo];
    
    return error;
}

- (NSError *)wrongClassErrorWithKey:(id<NSCopying>)key
                           valClass:(Class)valClass
                      expectedClass:(Class)expectedClass

{
    
    NSString *reasonStr = [NSString stringWithFormat:
                           @"key(%@)在字典中对应值的类型为[%@]，不是期望的类型[%@]",
                           key,
                           NSStringFromClass(valClass),
                           NSStringFromClass(expectedClass)];
    
    NSDictionary *errInfo = @{
                              NSLocalizedFailureReasonErrorKey:reasonStr,
                              };
    
    NSError *error = [NSError errorWithDomain:@"取出值的Class类型不是期望的"
                                         code:MZSafeDicErrorGetUnexpectedClass
                                     userInfo:errInfo];
    
    return error;
}

@end
